package com.xyy.saas.payment.adpater.abchinaLoan.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.xyy.ec.base.framework.rpc.ApiRPCResult;
import com.xyy.saas.payment.adpater.abchinaLoan.config.AbchinaLoanConfig;
import com.xyy.saas.payment.adpater.abchinaLoan.core.req.*;
import com.xyy.saas.payment.adpater.abchinaLoan.core.resp.OrderChangeNotifyResp;
import com.xyy.saas.payment.adpater.abchinaLoan.core.resp.OrderCheckResp;
import com.xyy.saas.payment.adpater.abchinaLoan.core.resp.QueryLoanStatusResp;
import com.xyy.saas.payment.adpater.abchinaLoan.support.AbchinaLoanClient;
import com.xyy.saas.payment.adpater.pingxx.domain.PayDO;
import com.xyy.saas.payment.callback.core.dto.CallbackMsg;
import com.xyy.saas.payment.callback.core.result.CallbackRunner;
import com.xyy.saas.payment.common.Constants;
import com.xyy.saas.payment.common.exception.PayBizException;
import com.xyy.saas.payment.common.exception.PaymentException;
import com.xyy.saas.payment.cores.enums.ChannelEnum;
import com.xyy.saas.payment.cores.enums.ResultCodeEnum;
import com.xyy.saas.payment.cores.vo.CallbackResultVo;
import com.xyy.saas.payment.dao.model.PayResultOrder;
import com.xyy.saas.payment.dao.model.PrePayOrder;
import com.xyy.saas.payment.payment.core.service.PrePayOrderService;
import com.xyy.saas.payment.service.PayResultOrderService;
import com.xyy.saas.payment.util.*;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.time.LocalDateTime;

/**
 * @author wangzeqi
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class AbchinaLoanService {

    private final AbchinaLoanConfig abchinaLoanConfig;
    private final AbchinaLoanClient abchinaLoanClient;
    @Resource
    private RedisUtil redisUtil;
    @Autowired
    private CallbackRunner callbackRunner;
    @Autowired
    private PayResultOrderService payResultOrderService;
    @Autowired
    private PrePayOrderService prePayOrderService;
    /**
     * 获取贷款申请单H5链接
     */
    public String applyH5(ApplyH5Dto applyH5Dto) {
        applyH5Dto.checkParam();
        String h5Url = abchinaLoanClient.applyH5(JSON.toJSONString(applyH5Dto));
        return h5Url;
    }

    /**
     * 贷款申请状态查询
     */
    public QueryLoanStatusResp queryLoanStatus(QueryLoanDto queryLoanDto) {
        queryLoanDto.checkParam();
        String logScene = "queryLoanStatus";
        String response = abchinaLoanClient.sendAndRecv(logScene, abchinaLoanConfig.getRequestUrl().getQueryLoanStatus(),
                JSON.toJSONString(queryLoanDto));
        QueryLoanStatusResp queryLoanStatusResp = JSON.parseObject(response, QueryLoanStatusResp.class);
        if (queryLoanStatusResp == null || StringUtils.isBlank(queryLoanStatusResp.getLoanStatus())) {
            throw new PayBizException("贷款申请状态查询，农行返回结果为空");
        }
        return queryLoanStatusResp;
    }

    /**
     * 订单支付资质校验
     */
    public OrderCheckResp orderCheck(OrderCheckDto orderCheckDto) {
        orderCheckDto.checkParam();
        String logScene = "orderCheck";
        String response = abchinaLoanClient.sendAndRecv(logScene, abchinaLoanConfig.getRequestUrl().getOrderCheck(),
                JSON.toJSONString(orderCheckDto));
        OrderCheckResp orderCheckResp = JSON.parseObject(response, OrderCheckResp.class);
        return orderCheckResp;
    }


    /**
     * 农行e贷
     * 退款，订单取消，订单状态主动查询都走这一个调用逻辑
     */
    public OrderChangeNotifyResp orderChangeNotify(OrderChangeDto orderChangeDto) {
        orderChangeDto.checkParam();
        String logScene = "orderChangeNotify";
        String response = abchinaLoanClient.sendAndRecv(logScene, abchinaLoanConfig.getRequestUrl().getOrderChangeNotify(),
                JSON.toJSONString(orderChangeDto));
        return JSON.parseObject(response, OrderChangeNotifyResp.class);
    }

    /**
     * 订单状态查询
     *
     * @param orderId 农行e贷订单号
     */
    public OrderChangeNotifyResp queryOrderStatus(String orderId) {
        if (StringUtils.isBlank(orderId)) {
            throw new PayBizException(ResultCodeEnum.PARAM_ERROR);
        }
        OrderChangeDto orderChangeDto = new OrderChangeDto()
                .setOrderId(orderId)
                .setChgType("2")
                .setTransTime(DateUtil.PATTERN_DATE.format(LocalDateTime.now()));
        String logScene = "queryOrderStatus";
        String response = abchinaLoanClient.sendAndRecv(logScene, abchinaLoanConfig.getRequestUrl().getOrderChangeNotify(),
                JSON.toJSONString(orderChangeDto));
        OrderChangeNotifyResp orderChangeNotifyResp = JSON.parseObject(response, OrderChangeNotifyResp.class);
        return orderChangeNotifyResp;
    }

    /**
     * 农行e贷 订单状态通知
     * @return
     */
    public ApiRPCResult orderStatusNotify(OrderStatusNotifyReq notifyReq) {
        // 暂只接 支付成功和取消
        if (!(Constants.AB_CHINA_ORDER_STATUS_PAY_SUCCESS.equals(notifyReq.getChgType()) || Constants.AB_CHINA_ORDER_STATUS_CANCEL.equals(notifyReq.getChgType()))) {
            log.info("orderStatusNotify not support chgType {} {}", notifyReq.getOrderId(), notifyReq.getChgType());
            return ApiRPCResult.buildSuccess(null);
        }
        String key = RedisUtil.AB_CHINA_PAY_NOTIFY + notifyReq.getOrderId();
        if(!redisUtil.setNx(key,"1",10)) {
            throw new PayBizException(ResultCodeEnum.PROFIT_SHARING_REPEAT_REQUEST);
        }

        // 查询预支付订单
        PrePayOrder prePayOrder = prePayOrderService.getPrePayOrderByPayNo(notifyReq.getOrderId());
        AssertUtil.notNull(prePayOrder, "未查到预支付单");

        //支付失败直接通知业务方
        if (Constants.AB_CHINA_ORDER_STATUS_CANCEL.equals(notifyReq.getChgType())) {
            // 异步回调业务
            String topic = ApolloUtil.getPaySuccessNotifyTopic(prePayOrder.getBusinessType(), prePayOrder.getBusinessOrderType());

            CallbackMsg callbackMsg = new CallbackMsg();
            callbackMsg.setTradeNo(prePayOrder.getPayNo());
            callbackMsg.setType(CallbackResultVo.PAY_FAIL);
            callbackMsg.setAmount(prePayOrder.getAmount());
            callbackMsg.setCallback(prePayOrder.getCallbackAddress());
            callbackMsg.setNotifyTime(DateUtil.now());
            callbackRunner.callback(topic, callbackMsg);
            return ApiRPCResult.buildSuccess(null);
        }

        // 幂等判断
        PayResultOrder payResultOrder = payResultOrderService.selectByPayNoAndChannel(notifyReq.getOrderId(), Constants.CHANNEL_ABCHINA_LOAN);

        if(payResultOrder != null) {
            log.error("AbchinaLoanService#orderStatusNotify repeat payNo:{}", notifyReq.getOrderId());
            return ApiRPCResult.buildSuccess(null);
        }

        PayDO payDO = buildPayDo(prePayOrder, notifyReq);
        if (!payDO.getAmount().equals(prePayOrder.getAmount())) {
            log.error("orderStatusNotify#amount error {} payDo:{} pay:{}", prePayOrder.getPayNo(), payDO.getAmount(), prePayOrder.getAmount());
            throw new PayBizException(ResultCodeEnum.PARAM_ERROR);
        }
        callbackRunner.callbackPingXX(payDO);
        return ApiRPCResult.buildSuccess(null);
    }

    private PayDO buildPayDo(PrePayOrder prePayOrder, OrderStatusNotifyReq notifyReq) {
        JSONObject extra = StringUtils.isBlank(prePayOrder.getExtra()) ? new JSONObject() : JSONObject.parseObject(prePayOrder.getExtra());
        // 基本参数
        PayDO payDO = new PayDO();
        payDO.setOrderNo(notifyReq.getOrderId());
        payDO.setAmount(AmountCastUtil.castYuan2Fen(notifyReq.getPayAmt()));
        payDO.setChannel(ChannelEnum.ABCHINA_LOAN.getCode());
        payDO.setPayMode(extra.getString("payMode"));
        payDO.setResultCode("SUCCESS");
//        payDO.setChannelTransactionNo(jdNotifyTradeVo.getLoanNo());
        payDO.setTimePaid(DateUtil.sdf1ToDate(notifyReq.getPayTime()));
        payDO.setFailureMsg("");
        // 其他参数
        payDO.setNotifyTime(DateUtil.now());
        payDO.setCount(0);
        payDO.setExtra(prePayOrder.getExtra());
        payDO.setBusinessType(prePayOrder.getBusinessType());
        payDO.setBusinessOrderType(prePayOrder.getBusinessOrderType());
        payDO.setReceiverId(prePayOrder.getReceiverId());
        payDO.setCallbackAddress(prePayOrder.getCallbackAddress());
        payDO.setPayer(prePayOrder.getPayer());
        payDO.setPayName(notifyReq.getCustName());
        payDO.setUscc(notifyReq.getUscc());
        payDO.setPayAcc(notifyReq.getPayAcc());
        return payDO;
    }
}
